package coreZapLog

import (
	"context"
	"errors"
	"fmt"
	"reflect"
	"time"

	"gitee.com/xgh2012/api-core/coreBiz"
	"gitee.com/xgh2012/api-core/coreMiddleware"

	"github.com/gin-gonic/gin"

	"go.uber.org/zap"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

type ZapGormLogger struct {
	ZapLogger     *zap.Logger
	LogLevel      logger.LogLevel
	SlowThreshold time.Duration
}

func NewGormLogger(zapLogger *zap.Logger, level logger.LogLevel, slowThreshold time.Duration) *ZapGormLogger {
	return &ZapGormLogger{
		ZapLogger:     zapLogger,
		LogLevel:      level,
		SlowThreshold: slowThreshold,
	}
}

func (l *ZapGormLogger) LogMode(level logger.LogLevel) logger.Interface {
	newLogger := *l
	newLogger.LogLevel = level
	return &newLogger
}

func (l *ZapGormLogger) Info(ctx context.Context, msg string, data ...interface{}) {
	if l.LogLevel >= logger.Info {
		traceFields := getTraceIDField(ctx)
		l.ZapLogger.Info(fmt.Sprintf(msg, data...), traceFields...)
	}
}

func (l *ZapGormLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
	if l.LogLevel >= logger.Warn {
		traceFields := getTraceIDField(ctx)
		l.ZapLogger.Warn(fmt.Sprintf(msg, data...), traceFields...)
	}
}

func (l *ZapGormLogger) Error(ctx context.Context, msg string, data ...interface{}) {
	if l.LogLevel >= logger.Error {
		traceFields := getTraceIDField(ctx)
		l.ZapLogger.Error(fmt.Sprintf(msg, data...), traceFields...)
	}
}

func (l *ZapGormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
	if l.LogLevel <= logger.Silent {
		return
	}
	elapsed := time.Since(begin)
	sql, rows := fc()
	fields := []zap.Field{
		zap.String("Sql语句", sql),
		zap.Int64("行数", rows),
		zap.Duration("耗时", elapsed),
	}
	traceFields := getTraceIDField(ctx)
	if len(traceFields) > 0 {
		fields = append(traceFields, fields...)
	}

	// 修改：ErrRecordNotFound 降级为 info
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			if l.LogLevel >= logger.Info {
				l.ZapLogger.Info("gorm 未查到记录", fields...)
			}
		} else if l.LogLevel >= logger.Error {
			l.ZapLogger.Error("gorm 错误", append(fields, zap.Error(err))...)
		}
	} else if l.SlowThreshold != 0 && elapsed > l.SlowThreshold && l.LogLevel >= logger.Warn {
		l.ZapLogger.Warn("gorm 慢查询", append(fields, zap.Duration("slow_threshold", l.SlowThreshold))...)
	} else if l.LogLevel >= logger.Info {
		l.ZapLogger.Info("gorm 执行", fields...)
	}
}

func getTraceIDField(c context.Context) []zap.Field {
	if c == nil {
		return nil
	}
	var ctx context.Context
	// 判断是否是 *gin.Context
	if reflect.TypeOf(c).String() == "*gin.Context" {
		ctx = coreMiddleware.CreateNewRequestContext(c.(*gin.Context))
	} else {
		ctx = c
	}
	var fields []zap.Field
	if traceID := coreMiddleware.GetTraceId(ctx); traceID != "" {
		fields = append(fields, zap.String(coreMiddleware.CtxKeyTraceId, traceID))
	}
	userInfo := coreMiddleware.GetUserInfo(ctx)
	if !coreBiz.IsEmpty(userInfo.Uid) {
		fields = append(fields, zap.String(coreMiddleware.CtxKeyUid, userInfo.Uid))
	}
	if !coreBiz.IsEmpty(userInfo.Mobile) {
		fields = append(fields, zap.String(coreMiddleware.CtxKeyMobile, userInfo.Mobile))
	}
	if !coreBiz.IsEmpty(userInfo.IdCard) {
		fields = append(fields, zap.String(coreMiddleware.CtxKeyIdCard, userInfo.IdCard))
	}
	if len(fields) > 0 {
		return fields
	}
	return nil
}
